import { EventClass } from "@lib/alen-helper/base/baseClass";
import { AppAisle } from "@lib/alen-helper/base/appAisle/";
import { MainSDK } from "./main.sdk";
import { concatMap, from, map, Subscription } from "rxjs";
import * as Path from "path";


export namespace WindowSDK {
    export interface Options {
        appid: string,
        aisle: AppAisle<MainSDK.CmdData>,
    }
}

export class WindowSDK extends EventClass<{
    close: {
        id: string,
        data: Runtime.OperatorCls.Window.Events['close'],
    },
    build: {
        id: string,
    },
    destroy: {
        id: string,
    },
    ready: {
        id: string,
    },
    show: {
        id: string,
    },
    hide: {
        id: string,
    },


    ipcActivate: {
        id: string, ipcAisle: AppAisle,
    },
    ipcReady: {
        id: string,
    },
    srcReady: {
        id: string,
    }
}> {
    constructor(
        public readonly options: WindowSDK.Options,
        BaseOptions?: Partial<EventClass.BaseOptions>
    ) {
        super('WindowSDK', BaseOptions);
    }

    get appid() {
        return this.options.appid;
    }

    get aisle() {
        return this.options.aisle;
    }

    private _handlers: AppAisle.CmdHandlers<Runtime.Controller.Window.CmdData_Client> = {
        window_event_close: (data, aisle) => {
            return this.triggerEventEnd('close', {
                id: data.data.param.id,
                data: data.data.param.data,
            })
                .pipe(map(e => ({
                    appid: this.appid,
                    id: e.id,
                    data: e.data,
                })));
        },
        window_event_build: (data, aisle) => {
            return this.triggerEventEnd('build', { id: data.data.param.id }).pipe(map(() => null));
        },
        window_event_destroy: (data, aisle) => {
            return this.triggerEventEnd('destroy', { id: data.data.param.id }).pipe(map(() => null));
        },
        window_event_ready: (data, aisle) => {
            return this.triggerEventEnd('srcReady', { id: data.data.param.id }).pipe(map(() => null));
        },
        window_event_show: (data, aisle) => {
            return this.triggerEventEnd('show', { id: data.data.param.id }).pipe(map(() => null));
        },
        window_event_hide: (data, aisle) => {
            return this.triggerEventEnd('hide', { id: data.data.param.id }).pipe(map(() => null));
        },
        window_event_state: (data, aisle) => {
            return null;
        },
    }

    private _setHandlers() {
        this.aisle.setHandler<Runtime.Controller.Window.CmdData_Client>(this._handlers);
    }

    itemIpcActivate(id: string, ipcAisle: AppAisle) {
        this.triggerEvent('ipcActivate', { id, ipcAisle });
    }

    itemIpcReady(id: string) {
        this.triggerEvent('ipcReady', { id });
    }

    itemReady(id: string) {
        this.triggerEvent('ready', { id });
    }


    windowItems: WindowItem[] = [];

    build(options: Partial<Runtime.OperatorCls.Window.Options>) {
        return this.aisle.cmd('window_build', { appid: this.appid, options })
            .pipe(map(id => {
                const item = this._newClass(WindowItem, id, this) as WindowItem;
                item.addEventHandler('destroy', () => {
                    let i = this.windowItems.indexOf(item);
                    if (i === -1) return;
                    this.windowItems.splice(i, 1);
                });
                this.windowItems.push(item);
                return item;
            }));
    }

    getItem(id: string) {
        for (let item of this.windowItems) {
            if (item.id === id) return item;
        }
        return null;
    }

    getItem_byIpcAisle(ipcAisle: AppAisle) {
        for (let item of this.windowItems) {
            if (item.ipcAisle === ipcAisle) return item;
        }
        return null;
    }

    init() {
        this._setHandlers();
    }
}

class WindowItem extends EventClass<{
    close: Runtime.OperatorCls.Window.Events['close'],
    destroy: null,
    ready: null,
    show: null,
    hide: null,
}> {
    constructor(
        public readonly id: string,
        public readonly windowSDK: WindowSDK,
        baseOptions?: Partial<EventClass.BaseOptions>,
    ) {
        super('WindowItem', baseOptions);
        this._sub();
        this._log.info(`window [ ${this.id} ] : build`);
    }

    get appid() {
        return this.windowSDK.appid;
    }

    private _ready = {
        ipc: false,
        src: false,
    };

    get isReady() {
        return this._ready.ipc && this._ready.src;
    }

    private _triggerReady() {
        if (!this.isReady) return;
        this.triggerEvent('ready', null);
        this.windowSDK.itemReady(this.id);
        this._log.info(`window [ ${this.id} ] : ready`);
    }

    private _subs: Subscription | null = null;
    private _hids: string[] = [];

    private _ipcAisle: AppAisle<Runtime.PreloadCmdData_Client> | null = null;

    get ipcAisle() {
        return this._ipcAisle;
    }

    private _unSub() {
        if (this._subs) this._subs.unsubscribe();
        this._subs = null;
        this.windowSDK.removeEventHandlerById(...this._hids);
        this._hids = [];
    }

    private _sub() {
        this._unSub();
        this._subs = this.event('destroy')
            .subscribe(() => {
                this._unSub();
                this.destroyEvent();
            });

        this._hids.push(
            this.windowSDK.addEventHandler('close', e => {
                if (e.data.id !== this.id) return;
                this._log.info(`window [ ${this.id} ] : close`);
                return this.triggerEventEnd('close', e.data.data)
                    .pipe(map(back => {
                        e.data.data = back;
                    }));
            }),

            this.windowSDK.addEventHandler('destroy', e => {
                if (e.data.id !== this.id) return;
                this._log.info(`window [ ${this.id} ] : destroy`);
                this.triggerEvent('destroy', null);
            }),

            this.windowSDK.addEventHandler('srcReady', e => {
                if (e.data.id !== this.id) return;
                this._ready.src = true;
                this._triggerReady();
            }),

            this.windowSDK.addEventHandler('ipcReady', e => {
                if (e.data.id !== this.id) return;
                this._ready.ipc = true;
                this._triggerReady();
            }),

            this.windowSDK.addEventHandler('ipcActivate', e => {
                if (e.data.id !== this.id) return;
                this._ipcAisle = e.data.ipcAisle;
            }),

            this.windowSDK.addEventHandler('show', e => {
                if (e.data.id !== this.id) return;
                this._log.info(`window [ ${this.id} ] : show`);
                this.triggerEvent('show', null);
            }),

            this.windowSDK.addEventHandler('hide', e => {
                if (e.data.id !== this.id) return;
                this._log.info(`window [ ${this.id} ] : hide`);
                this.triggerEvent('hide', null);
            }),
        );
    }

    hide() {
        return this.windowSDK.aisle.cmd('window_hide', { appid: this.appid, id: this.id });
    }

    show() {
        return this.windowSDK.aisle.cmd('window_show', { appid: this.appid, id: this.id });
    }

    close() {
        return this.windowSDK.aisle.cmd('window_close', { appid: this.appid, id: this.id });
    }

    destroy() {
        return this.windowSDK.aisle.cmd('window_destroy', { appid: this.appid, id: this.id });
    }
}